#ifndef BT_API_LE_H
#define BT_API_LE_H

// #define BLE_USE_EXTEND_ADV              1

#define LE_ERR_OK                       0x00
#define LE_ERR_INVALID_HANDLE           0x01
#define LE_ERR_READ_NOT_PERMITTED       0x02
#define LE_ERR_WRITE_NOT_PERMITTED      0x03
#define LE_ERR_INVALID_PDU              0x04
#define LE_ERR_INSUFFICIENT_AUTHEN      0x05
#define LE_ERR_REQUEST_NOT_SUPPORT      0x06
#define LE_ERR_INVALID_OFFSET           0x07
#define LE_ERR_INSUFFICIENT_AUTHOR      0x08
#define LE_ERR_PREPARE_QUEUE_FULL       0x09
#define LE_ERR_ATTRIBUTE_NOT_FOUND      0x0A
#define LE_ERR_ATTRIBUTE_NOT_LONG       0x0B
#define LE_ERR_INSUFFICIENT_ENCRY_KEY   0x0C
#define LE_ERR_INVALID_ATTRIBUTE_VALUE  0x0D
#define LE_ERR_UNLIKELY_ERROR           0x0E
#define LE_ERR_INSUFFICIENT_ENCRY       0x0F
#define LE_ERR_UNSUPPORTED_GTOUP_TYPE   0x10
#define LE_ERR_INSUFFICIENT_RESOURCES   0x11

#define LE_DEVICE_TYPE_CLASSIC          1
#define LE_DEVICE_TYPE_DUAL             3
#define LE_DEVICE_TYPE_LE               2
#define LE_DEVICE_TYPE_UNKNOWN          0

#define LE_ADV_TYPE_IND                 0x00
#define LE_ADV_TYPE_DIRECT_IND          0x01
#define LE_ADV_TYPE_SCAN_IND            0x02
#define LE_ADV_TYPE_NONCONN_IND         0x03
#define LE_ADV_TYPE_DIRECT_IND_LOW_DUTY 0x04

#define LE_EXT_ADV_PROPERTIES_BIT_CONNECTABLE   0
#define LE_EXT_ADV_PROPERTIES_BIT_SCANNABLE     1
#define LE_EXT_ADV_PROPERTIES_BIT_DIRECTED      2
#define LE_EXT_ADV_PROPERTIES_BIT_HIGH_DUTY_DIRECTED_CONNECTABLE  3
#define LE_EXT_ADV_PROPERTIES_BIT_LEGACY        4
#define LE_EXT_ADV_PROPERTIES_BIT_OMIT          5
#define LE_EXT_ADV_PROPERTIES_BIT_TXPOWER       6

#define LE_ADDRESS_TYPE_PUBLIC          0x00
#define LE_ADDRESS_TYPE_RANDOM          0x01

#define LE_GAP_TYPE_FLAGS                       0x01
#define LE_GAP_TYPE_INCOMPLETE_SERVICE_16BIT_LIST       0x02
#define LE_GAP_TYPE_COMPLETE_SERVICE_LIST       0x03
#define LE_GAP_TYPE_SHORT_NAME                  0x08
#define LE_GAP_TYPE_COMPLETE_NAME               0x09
#define LE_GAP_TYPE_TX_POWER                    0x0A
#define LE_GAP_TYPE_SERVICE_DATA                0x16
#define LE_GAP_TYPE_APPEARANCE                  0x19
#define LE_GAP_TYPE_SPECIFIC_DATA               0xFF

#define LE_PASSIVE_SCAN                 0x00
#define LE_ACTIVE_SCAN                  0x01

#define LE_ATT_MASTER                   0
#define LE_ATT_SLAVE                    1

#define LE_CCC_BIT_INDICATED            0x02
#define LE_CCC_BIT_NOTIFIED             0x01

#define LE_ATT_CHARC_PROP_READ          0x02
#define LE_ATT_CHARC_PROP_WWP           0x04
#define LE_ATT_CHARC_PROP_WRITE         0x08
#define LE_ATT_CHARC_PROP_NOTIFY        0x10
#define LE_ATT_CHARC_PROP_INDICATE      0x20

#define LE_ATT_PM_READABLE              0x0001
#define LE_ATT_PM_WRITEABLE             0x0002
#define LE_ATT_PM_AUTHENT_REQUIRED      0x0004
#define LE_ATT_PM_AUTHORIZE_REQUIRED    0x0008
#define LE_ATT_PM_ENCRYPTION_REQUIRED   0x0010
#define LE_ATT_PM_AUTHENT_MITM_REQUERED 0x0020

#define LE_ATT_UUID_PRIMARY             0x2800
#define LE_ATT_UUID_CHARC               0x2803

// standard GATT descriptors
#define LE_ATT_UUID_CLIENT_CHARC_CONFIG 0x2902
#define LE_ATT_UUID_CHAR_PRESENT_FORMAT 0x2904
#define LE_ATT_UUID_EXTERNAL_REF        0x2907
#define LE_ATT_UUID_REPORT_REF          0x2908


#define LE_ATT_UUID_IMMEDIATE_ALERT     0x1802
#define LE_ATT_UUID_DEVICE_INFO         0x180A
#define	LE_ATT_UUID_BATTERY_SERVICE		0x180F
#define	LE_ATT_UUID_HID					0x1812
#define LE_ATT_UUID_MESH_PRO_SERVICE    0x1827
#define LE_ATT_UUID_MESH_PROXY_SERVICE  0x1828

#define LE_ATT_UUID_ALERT_LEVEL         0x2A06
#define LE_ATT_UUID_BATTERY   			0x2A19
#define LE_ATT_UUID_HIDBOOT_KB_INPUT	0x2A22
#define LE_ATT_UUID_HIDBOOT_KB_OUTPUT	0x2A32
#define LE_UUID_HIDBOOT_MOUSE_INPUT	    0x2A33

#define LE_ATT_UUID_HIDINFO   			0x2A4A
#define LE_ATT_UUID_HIDREPORT_MAP		0x2A4B

#define LE_ATT_UUID_HIDCONTROLPOINT   	0x2A4C
#define LE_ATT_UUID_PROTOCOL   		    0x2A4E

#define LE_ATT_UUID_HIDREPORT   		0x2A4D
#define LE_ATT_UUID_ALERT_LEVEL         0x2A06

#define LE_ATT_UUID_SYSTEM_ID           0x2A23
#define LE_ATT_UUID_MODEL_NUMBER        0x2A24
#define LE_ATT_UUID_SERIAL_NUMBER       0x2A25
#define LE_ATT_UUID_FIRMWARE_VERSION    0x2A26
#define LE_ATT_UUID_HARDWARE_VERSION    0x2A27
#define LE_ATT_UUID_SOFTWARE_VERSION    0x2A28
#define LE_ATT_UUID_MANUFACTURER_NAME   0x2A29
#define LE_ATT_UUID_IEEE_LIST           0x2A2A
#define LE_ATT_UUID_PNP_ID   			0x2A50

#define LE_ATT_UUID_MESH_PRO_DATA_IN    0x2ADB
#define LE_ATT_UUID_MESH_PRO_DATA_OUT   0x2ADC
#define LE_ATT_UUID_MESH_PROXY_DATA_IN  0x2ADD
#define LE_ATT_UUID_MESH_PROXY_DATA_OUT 0x2ADE

typedef struct
{
	unsigned short configurationBits;
	struct bt_addr addr;
}gatt_chara_ccb_ex_t;

struct le_uuid {
    unsigned char type;
};

struct le_uuid_16 {
    struct le_uuid uuid;
    unsigned short value;
};

struct le_uuid_32 {
    struct le_uuid uuid;
    unsigned int value;
};

struct le_uuid_128 {
    struct le_uuid uuid;
    unsigned char value[16];
};

struct le_uuid_common {
    unsigned char type;

    union {
        struct le_uuid_16 uuid_16;
        struct le_uuid_32 uuid_32;
        struct le_uuid_128 uuid_128;
    } u;
};

struct gatt_attr {
    struct le_uuid *uuid;
    void *value;
    int size;
    unsigned short handle;
    unsigned char permission;
    int (*write_cb)(void *arg);
    int (*read_cb)(void *arg);
};

#pragma pack(1)
struct gatt_chrc {
    unsigned char properties;
    unsigned short handle;
    unsigned short uuid;
};

struct gatt_chrc128 {
    unsigned char properties;
    unsigned short handle;
    unsigned char uuid[16];
};

#pragma pack()

struct gatt_attr_rw_parameters {
    unsigned short handle;
    unsigned short length; /* how many bytes want read or write */
    unsigned short offset; /* read write from where */
    unsigned char *data; /* for write operation: this is contains the data to be written;
                            for read operation: user should alloc memory and fill data to here, then return buffer size*/
};

#define LE_UUID_TYPE_16     (2)
#define LE_UUID_TYPE_32     (4)
#define LE_UUID_TYPE_128    (16)

extern struct le_uuid_16 LE_UUID_PERIMARY_SERVICE;

extern struct le_uuid_16 LE_UUID_CLIENT_CHARC_CONFIG;

extern struct le_uuid_16 LE_UUID_CHARACTERISTIC;

extern struct le_uuid_16 LE_UUID_REPORT_REF_CHARC_CONFIG;

extern struct le_uuid_16 LE_UUID_CHAR_PRESENTATION_FORMAT;


#define LE_DECLARE_PRIMARY_SERVICE(_UUID_, _UUID_TYPE_)  \
    {.uuid = (struct le_uuid *)&LE_UUID_PERIMARY_SERVICE, \
     .value = (void *)&(_UUID_.value), .size = _UUID_TYPE_, \
     .permission = LE_ATT_PM_READABLE}

#define LE_DECLARE_CHARACTERISTIC(_CHARACTERISTIC_, _UUID_, _PERMISSION_, _WCB_, _RCB_, _VALUE_, _VALUE_SIZE_) \
    {.uuid = (struct le_uuid *)&LE_UUID_CHARACTERISTIC, \
     .value = (void *)&_CHARACTERISTIC_, \
     .size = sizeof(_CHARACTERISTIC_), \
     .permission = LE_ATT_PM_READABLE}, \
    {.uuid = (struct le_uuid *)&_UUID_, \
     .value = (void *)_VALUE_, .size = _VALUE_SIZE_, \
     .permission = _PERMISSION_, \
     .write_cb = _WCB_, .read_cb = _RCB_}

#define LE_DECLARE_CLINET_CHRAC_CONFIG(_VALUE_, _WCB_) \
    {.uuid = (struct le_uuid *)&LE_UUID_CLIENT_CHARC_CONFIG, \
     .value = (void *)&_VALUE_, \
     .size = sizeof(_VALUE_), \
     .permission = LE_ATT_PM_READABLE | LE_ATT_PM_WRITEABLE, \
     .write_cb = _WCB_}

#define LE_DECLARE_REPORT_REF_CHRAC_CONFIG(_VALUE_, _RCB_, SIZE) \
    {.uuid = (struct le_uuid *)&LE_UUID_REPORT_REF_CHARC_CONFIG, \
     .value = (void *)_VALUE_, \
     .size = SIZE, \
     .permission = LE_ATT_PM_READABLE, \
     .read_cb = _RCB_}

#define LE_DECLARE_REPORT_PRESENTATION_FORMAT(_VALUE_, _RCB_, SIZE) \
    {.uuid = (struct le_uuid *)&LE_UUID_CHAR_PRESENTATION_FORMAT, \
     .value = (void *)_VALUE_, \
     .size = SIZE, \
     .permission = LE_ATT_PM_READABLE, \
     .read_cb = _RCB_}



typedef void (*le_scan_event_handle_t)(struct bt_event_le_scan_event *event);

typedef int (*le_att_event_handle_t)(struct bt_task_event * msg);


#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

int appbt_le_set_random_address(struct bt_addr addr);

int appbt_le_create_adv_data(int gap,
                             unsigned char *buffer, int buffer_size,
                             unsigned char *data, int size);

int appbt_le_parse_device_type(unsigned char * data, int total_size);

int appbt_le_set_adv_parameters(struct bt_task_le_adv_parameters *para);

int appbt_le_set_adv_data(unsigned char *data, unsigned char length);

int appbt_le_set_scan_response_data(unsigned char *data, unsigned char length);

int appbt_le_set_adv_enable(int enable);

int appbt_le_set_ext_adv_parameters(struct bt_task_le_ext_adv_parameters *para);

int appbt_le_set_adv_set_random_address(unsigned char handle, struct bt_addr addr);

int appbt_le_set_ext_adv_data(unsigned char *data, unsigned char length,
            unsigned char handle, unsigned char operation, unsigned char fragment);

int appbt_le_set_ext_scan_response(unsigned char *data, unsigned char length,
            unsigned char handle, unsigned char operation, unsigned char fragment);

int appbt_le_set_ext_adv_enable(unsigned char enable, unsigned char number,
        unsigned char handle[], unsigned short duration[], unsigned char max_event[]);

// API: read LE adv physical channel tx power
// the read result indicated throught event BTTASK_IND_ADV_PHY_TXPOWER
int appbt_le_read_adv_phy_txpower(void);

int appbt_le_scan(unsigned char type,
                  unsigned short int interval,
                  unsigned short int window,
                  unsigned char own_address_type,
                  le_scan_event_handle_t handle);

int appbt_le_clear_white_list(void);

int appbt_le_set_white_list(struct bt_addr addr, unsigned char type);

int appbt_le_scan_stop(void);

int appbt_le_register_service(struct gatt_attr *service, int count);

int appbt_le_unregister_service(void);

int appbt_le_update_attribute(struct gatt_attr *attribute);

int appbt_le_notify(unsigned short att_handle, unsigned char *data, int size);

int appbt_le_indicate(unsigned short att_handle, unsigned char *data, int size, void (*cb)(void));

int appbt_le_register_att_event_handle(le_att_event_handle_t handle);

int appbt_le_connect(struct bt_addr addr, int type);

int appbt_le_disconnect(void);

int appbt_le_mtu_request(unsigned short acl_handle);

int appbt_le_read_by_group_type_request
    (unsigned short start, unsigned short end, unsigned short uuid);

int appbt_le_read_by_type_request
    (unsigned short start, unsigned short end, unsigned short uuid);

int appbt_le_find_information_request
    (unsigned short start, unsigned short end);

// API: write data to remote device
// type: BTTASK_CMD_LE_WRITE_COMMAND or BTTASK_CMD_LE_WRITE_REQUEST
int appbt_le_write(int type, unsigned short att_handle,
        unsigned char *data, unsigned short size);
// API: read data from remote device
int appbt_le_read(unsigned short att_handle);

// API: for SMP start
int appbt_le_smp_initiate(struct bt_addr addr);

// API: for clear pair info
int appbt_le_clear_pair_info(void);

// API: for dump pair info
int appbt_le_dump_pair_info(void);

// API: for reload pair info
int appbt_le_reload_pair_info(void);

// API: for set passkey form local
/**
 * @param result: pair result, 0: success, 1: fail
 * @param reason: reason when result is fail
 */
typedef void (*pair_result_callback)(unsigned char result, unsigned char reason);

/**
 * @param set_enable: set enable passkey set, 0: disable, 1: enable
 * @param passkey: passkey for user input(from 0 ~ 999999)
 * @param callback: register callback to monitor pair result
 */
int appbt_le_set_passkey_from_local(unsigned char set_enable, unsigned int passkey, pair_result_callback callback);

// API: for set pair enable/disable
int appbt_le_set_pair_enable(unsigned char set_enable);

// API: for le client att read of hoststack
int appbt_le_client_read(unsigned short att_handle);

// API: for le client att event handle of hoststack
int le_client_att_event_handle(struct bt_task_event * msg);

#ifdef __cplusplus
}
#endif // __cplusplus

#endif

